package views

import (
	"bytes"
	"strings"
	"net/http"
	"net/url"
	"encoding/json"
	"appengine"
	"appengine/user"
	"mdbook/model/post"
	"mdbook/gorilla/context"
)

type content struct {
	*tplModel
	Header		string
	Content		string
	Footer		string
}

type tplModel struct {
	*Config
	CanBack		bool
	Logined		bool
	IsAdmin		bool
	IsMobile	bool
	User		string
	LoginUrl	string
	LogoutUrl	string
	ThemePath	string
	Path		string
	Title		string
	Post		*post.Snapshot
}

const tplKey 	string = "tpl_key"
const tplMobile	string = "tpl_mobile"

func detectMobile(agent string) bool {
	if	strings.Index(agent, "Mobile") >= 0 ||
		strings.Index(agent, "Phone") >= 0 ||
		strings.Index(agent, "Android") >= 0 ||
		strings.Index(agent, "iPhone") >= 0 ||
		strings.Index(agent, "iPad") >= 0 ||
		strings.Index(agent, "iPod") >= 0 ||
		strings.Index(agent, "Symbian") >= 0 {
		
		return true
	}
	return false
}

func newModel(req *http.Request, title string, post *post.Snapshot) *tplModel {
	ctx := appengine.NewContext(req)
	m := &tplModel{Config:cfg}

	ref := req.Header.Get("Referer")
	if ref != "" {
		f, _ := url.Parse(ref)
		if 	f.Host == req.Host &&
			f.Path != req.URL.Path &&
			strings.Index(f.Path, "/_") != 0 {

			m.CanBack = true
		}
	}

	if u := user.Current(ctx); u != nil {
		m.Logined = true
		m.User = u.String()
		if u.Admin {
			m.IsAdmin = true
		}
	}

	agent := req.UserAgent()
	if detectMobile(agent) {
		m.IsMobile = true
		m.ThemePath = "/themes/" + cfg.Mobile
		context.Set(req, tplMobile, true)
	} else {
		m.ThemePath = "/themes/" + cfg.Theme
	}

	m.LoginUrl, _ = user.LoginURL(ctx, req.URL.String())
	m.LogoutUrl, _ = user.LogoutURL(ctx, req.URL.String())

	if post != nil {
		m.Title = post.Title
		m.Post = post
	} else {
		m.Title = title
	}

	m.Path = req.URL.Path
	//ctx.Infof("IsMobile: %v", agent)
	return m
}

// 公共页面处理
func parseTemplate(req *http.Request, file string, data interface{}) (out []byte, error error) {
	t := "view"
	if _t := context.Get(req, tplKey); _t != nil {
		t = _t.(string)
	} else if m := context.Get(req, tplMobile); m != nil && m.(bool) {
		t = "mobile"
	}

	var buf bytes.Buffer
	err := tmpls[t].ExecuteTemplate(&buf, file, data)
	if err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}

func renderView(req *http.Request, file string, model *tplModel) ([]byte, error) {
	header, err := parseTemplate(req, "header.tpl", model)
	if err != nil {
		return nil, err
	}

	footer, err := parseTemplate(req, "footer.tpl", model)
	if err != nil {
		return nil, err
	}
	page, err := parseTemplate(req, file, model)
	if err != nil {
		return nil, err
	}
	base, err := parseTemplate(req, "base.tpl", content{model, string(header), string(page), string(footer)})
	if err != nil {
		return nil, err
	}
	return base, nil
}

func renderJSON(w http.ResponseWriter, r *http.Request, v interface{}) {
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	b, _ := json.Marshal(v)
	w.Write(b)
}

func render404(w http.ResponseWriter, req *http.Request, path string) {
	w.WriteHeader(http.StatusNotFound)
	model := newModel(req, "404", nil)
	view, _ := renderView(req, "404.tpl", model)
	w.Write(view)
}

func renderError(w http.ResponseWriter, req *http.Request, err error) {
	ctx := appengine.NewContext(req)
	w.WriteHeader(http.StatusInternalServerError)
	ctx.Errorf("%v", err)

	model := newModel(req, "500", nil)
	view, _ := renderView(req, "500.tpl", model)
	w.Write(view)
}
